﻿using System;
using System.Collections;
using System.Security.Policy;
using UnityEditor.VersionControl;
using UnityEngine;

namespace Component
{
    public class CameraTools
    {
        public static readonly Camera MainCamera = Camera.main;
        private static readonly Transform CameraTransform = MainCamera.transform;
        private static float originSize;
        private static Task orthographicTask;
        
        static CameraTools()
        {
            originSize = MainCamera.orthographicSize;
        }

        public static void ResetCameraSize(float size = 0)
        {
            MainCamera.orthographicSize = size == 0 ? originSize : size;
        }
        
        public static Vector2 GetCursor()
        {
            return MainCamera.ScreenToWorldPoint(Input.mousePosition);
        }

        public static Ray ScreenRayHitInfo(Vector2 point)
        {
            return MainCamera.ScreenPointToRay(point);
        }
        
        public static Vector2 ScreenToWorldPoint(Vector2 point)
        {
            return MainCamera.ScreenToWorldPoint(point);
        }

        public static void CameraFollow(Vector2 target, float time,Vector3 angle, Action callback, Action completeEvent)
        {
            LeanTween.move(MainCamera.gameObject, target, time).setDelay(.3f).setOnComplete(completeEvent.Invoke);
            LeanTween.rotate(MainCamera.gameObject, angle, .6f).setDelay(.3f);
            callback.Invoke();
        }

        public static void CameraSizeFollow(float target, float time)
        {
            float offset = target - MainCamera.orthographicSize;
            var task = new Task(SizeUpdate(offset, time, false));

        }

        public static IEnumerator SizeUpdate(float offset, float time, bool bounce)
        {
            if (orthographicTask != null)
            {
                orthographicTask.Stop();
            }
            float origin = MainCamera.orthographicSize;
            float current = 0;

            float timer = 0;
            float delta = Mathf.PI / (time / Time.fixedDeltaTime) / (bounce ? 1 : 2);

            while (timer < time)
            {
                MainCamera.orthographicSize = origin + offset * Mathf.Sin(current);
                yield return new WaitForSeconds(Time.fixedDeltaTime);
                timer += Time.fixedDeltaTime;
                current += delta;
            }

            MainCamera.orthographicSize = bounce ? origin : offset + origin;

        }

        public static void SizeUpdateHelper(float offset, float time, bool bounce, Action onComplete)
        {
            var task = new Task(SizeUpdate(offset, time, bounce));
            task.Finished += delegate(bool manual)
            {
                onComplete.Invoke();
                MoveVector.maxSize = MainCamera.orthographicSize + 1;
            };
        }

        public static void OrthographicSizeBigger(float offset)
        {
            var orthographicTask = new Task(OrthographicSizeHelper(offset));
            orthographicTask.Finished += delegate(bool manual)
            {
                SetMaxSize(offset);
            };
        }
        
        private static IEnumerator OrthographicSizeHelper(float offset)
        {
            var target = MainCamera.orthographicSize + offset;
            var delta = offset / Mathf.Abs(offset);
            while (Mathf.Abs(target - MainCamera.orthographicSize) > .05f)
            {
                Debug.Log(Mathf.Abs(target - MainCamera.orthographicSize));
                MainCamera.orthographicSize += delta * .00008f;
                yield return new WaitForSeconds(Time.deltaTime);
            }
        }

        public static void SetBounds(Vector3 bounds)
        {
            MoveVector = new CameraMoveVector(bounds, CameraTransform.position, null, Vector3.zero);
        }

        public static void SetMaxSize(float offset)
        {
            MoveVector.maxSize += offset;
        }

        private static CameraMoveVector MoveVector;
        
        public static void DragCamera(Action<bool> callback) 
        {
            if (!MoveVector.init)
            {
                return;
            }
            
            if (Input.GetMouseButton(0))
            {
                MoveVector.desc?.reset();
                var position = CameraTransform.position;
                
                Vector3 newPosition = position - (CameraTransform.right * Input.GetAxis("Mouse X") + 
                                                  MainCamera.transform.up * Input.GetAxis("Mouse Y")) * (1 * Time.timeScale);
                newPosition = new Vector3(
                    Mathf.Clamp(newPosition.x, MoveVector.boundsPosition.x - MoveVector.bounds.x, MoveVector.boundsPosition.x + MoveVector.bounds.x),
                    Mathf.Clamp(newPosition.y, MoveVector.boundsPosition.y - MoveVector.bounds.y, MoveVector.boundsPosition.y + MoveVector.bounds.y),
                    Mathf.Clamp(newPosition.z, MoveVector.boundsPosition.z - MoveVector.bounds.z, MoveVector.boundsPosition.z + MoveVector.bounds.z));
                position = Vector3.SmoothDamp(position, newPosition,  ref MoveVector.current, .5f);
                CameraTransform.position = position;
                callback.Invoke(false);
            }

            if (Input.GetMouseButtonUp(0))
            { 
                MoveVector.desc = LeanTween.move(MainCamera.gameObject, MoveVector.boundsPosition, .5f).setEase(LeanTweenType.linear);
                callback.Invoke(true);
            }
        }

        public static void CameraZoom()
        {
            //Zoom out
            if (Input.GetAxis("Mouse ScrollWheel") < 0)
            {
                if (MainCamera.orthographicSize <= MoveVector.maxSize + .5f)
                {
                    float size = Mathf.SmoothDamp(MainCamera.orthographicSize, MoveVector.maxSize,
                        ref MoveVector.SizeVelocity, .5f);
                    MainCamera.orthographicSize = size;
                }
            }
            else if (Input.GetAxis("Mouse ScrollWheel") > 0)
            {
                if (MainCamera.orthographicSize > MoveVector.MinSize)
                {
                    MainCamera.orthographicSize -= .2f;
                }
            }
            // else
            // {
            //     if (MainCamera.orthographicSize > MoveVector.maxSize)
            //     {
            //         float size = Mathf.SmoothDamp(MainCamera.orthographicSize, MoveVector.maxSize,
            //             ref MoveVector.SizeVelocity, .5f);
            //         MainCamera.orthographicSize = size;
            //     }
            // }
        }
        
        public struct CameraMoveVector
        {
            public Vector3 bounds;
            public Vector3 boundsPosition;
            public LTDescr desc;
            public Vector3 current;
            public bool init;
            public float maxSize;
            public float MinSize;
            public float SizeVelocity;
            
            public CameraMoveVector(Vector3 bounds, Vector3 boundsPosition, LTDescr desc, Vector3 current)
            {
                this.bounds = bounds;
                this.boundsPosition = boundsPosition;
                this.desc = desc;
                this.current = current;
                init = true;
                MinSize = MainCamera.orthographicSize;
                maxSize = MinSize;
                SizeVelocity = 0;
            }
        }
        
    }
}